package cn.mugutu.finance.aop;

import cn.mugutu.finance.annotation.SysLog;
import cn.mugutu.finance.domain.system.Log;
import cn.mugutu.finance.domain.system.User;
import cn.mugutu.finance.listener.event.LogEvent;
import cn.mugutu.finance.utils.ConstantConfig;
import cn.mugutu.finance.enums.LogTyep;
import cn.mugutu.finance.utils.RequestHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * 日志记录切面
 */
@Aspect
@Component
public class LogAop implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    private static final Logger logger = LoggerFactory.getLogger(LogAop.class);

    @Pointcut("@annotation(cn.mugutu.finance.annotation.SysLog)")
    private void businessLogAspect() {}

    @Pointcut("execution (* cn.mugutu.finance.controller..*(..))")
    private void exceptionLogAspect() {}

    /**
     * 系统异常日志
     */
    @AfterThrowing(pointcut = "exceptionLogAspect()", throwing = "e")
    public void doAfterThrow(JoinPoint joinPoint, Throwable e) {
        try {
            HttpServletRequest request = RequestHolder.getRequest();
            HttpSession session = request.getSession();
            User loginUser = (User) session.getAttribute(ConstantConfig.USER_IN_SESSION);
            String exceptionMethod = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName();

            Log log = new Log();
            log.setUserId(loginUser.getId());
            log.setUsername(loginUser.getUsername() + "/" + loginUser.getRealname());
            log.setMethods(exceptionMethod);
            log.setRequestIp(request.getRemoteAddr());
            log.setOperTime(new Date());
            log.setLogTyep(LogTyep.EXCEPTIONLOG);  //异常日志
            log.setExceptionMsg(e.getMessage());

            applicationEventPublisher.publishEvent(new LogEvent(log));  //发布记录日志事件

        } catch (Exception e2) {
            e2.printStackTrace();
            //暂时做记录本地日志异常,以后加入统一异常管理
            logger.error("记录系统异常日志发生异常,异常消息:{}" + e2);
        }
    }

    /**
     * 系统运行日志
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("businessLogAspect()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature methodSign;
        if (pjp.getSignature() instanceof MethodSignature) {
            methodSign = (MethodSignature) pjp.getSignature();
        } else {
            return pjp.proceed();
        }

        long startTime = System.currentTimeMillis();
        Object obj = pjp.proceed(); //执行该方法
        long endTime = System.currentTimeMillis();

        try {
            HttpServletRequest request = RequestHolder.getRequest();
            HttpSession session = request.getSession();
            User loginUser = (User) session.getAttribute(ConstantConfig.USER_IN_SESSION);
            String method = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
            String sysLogAnnotationDescription = methodSign.getMethod().getAnnotation(SysLog.class).description();

            Log log = new Log();
            log.setUserId(loginUser.getId());
            log.setUsername(loginUser.getUsername() + "/" + loginUser.getRealname());
            log.setRequestIp(request.getRemoteAddr());
            log.setOperTime(new Date());
            log.setMethods(method);
            log.setDescription(sysLogAnnotationDescription);
            log.setLogTyep(LogTyep.BUSINESSLOG);  //异常日志
            log.setResponseTime(endTime - startTime);
            applicationEventPublisher.publishEvent(new LogEvent(log));  //发布记录日志事件

        } catch (Exception e2) {
            e2.printStackTrace();
            logger.error("记录日志运行日志发生异常,异常信息:{}" + e2);
        }
        return obj;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
